package com.ethan.ebind.compiler;

import com.ethan.ebind.annotations.Ebv;
import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;

@AutoService(Processor.class)
public class EbindProcess extends AbstractProcessor {
    Messager messager;
    Filer mFiler;
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
        mFiler = processingEnv.getFiler();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String>set = new HashSet<>();
        set.add(Ebv.class.getCanonicalName());
        return set;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {



        Set<? extends Element> elements  =  roundEnv.getElementsAnnotatedWith(Ebv.class);
        Map<TypeElement,Set<Element>>resultMap  = filterMapByClsName(elements);
        resultMap.forEach((c,p)->{
            //MainActivityl类名
            String clsNameStr = c.getSimpleName().toString();
            System.out.println(  "---------1");
            PackageElement packageElement = (PackageElement) c.getEnclosingElement();

            String  pkgStr = packageElement.getQualifiedName().toString();
            ClassName className = ClassName.get(pkgStr, clsNameStr);

           FieldSpec target = FieldSpec.builder(className, "target")
                    .addModifiers(Modifier.PRIVATE)
                    .build();
            System.out.println(  "---------2");
            String tyleClsName = clsNameStr+"_ViewBinding";

            TypeSpec.Builder clsBuilder = TypeSpec.classBuilder(tyleClsName)
                    .addModifiers(Modifier.PUBLIC);

            MethodSpec.Builder methodBulder = MethodSpec.constructorBuilder()
                    .addModifiers(Modifier.PUBLIC)
                    .addParameter(className, "target")
                    .addStatement("this.target = target");

            MethodSpec.Builder unBindMethod = MethodSpec.methodBuilder("unbind").addAnnotation(Override.class)
                    .addModifiers(Modifier.PUBLIC);
            p.stream().forEach(v->{
                Ebv ebv = v.getAnnotation(Ebv.class);
                methodBulder.addStatement("target.$L=target.findViewById($L)",v.getSimpleName().toString(), ebv.value());
            });
            try {
                clsBuilder.addField(target)
                        .addMethod(methodBulder.build())
                        .addMethod(unBindMethod.build())
                        .addSuperinterface(ClassName.get("com.ethan.ebind","Unbinder"));
                JavaFile javaFile = JavaFile.builder(pkgStr, clsBuilder.build()).build();
                javaFile.writeTo(mFiler);
                System.out.println(  "---------2");
            }catch (Exception e){
                e.printStackTrace();
            }


        });


        return false;
    }


    private Map<TypeElement, Set<Element>> filterMapByClsName( Set<? extends Element> elements) {
        Map<TypeElement,Set<Element>>resultMap = new HashMap<>();
        for (Element e : elements) {
            TypeElement enclosingElement = (TypeElement) e.getEnclosingElement();
            Set<Element> tmpSet = resultMap.get(enclosingElement);
            System.out.println(  "---------"+e.getSimpleName());
            if (tmpSet == null) tmpSet = new HashSet<>();
            tmpSet.add(e);
            resultMap.put(enclosingElement, tmpSet);
        }
        return resultMap;
    }
}
